﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Data;
using System.Data.OleDb;
using lo = sqCore.sqLogger;
using MongoDB.Driver;
using MongoDB.Driver.Linq;
using MongoDB.Bson;
using MongoDB.Bson.IO;
using MongoDB.Driver.Builders;
using MongoDB.Bson.Serialization.Attributes;


namespace sqCore
{
    /* Docs:
     * Summary
        * Mongo query Job object for SqlA Tasks.
     * Override Variables
        * IsDone - If false, this job not runed.
        * ExecuteTime - Time that the job executed.
        * Result - The results of the execute.
     * Variables
        * DB - SqlA db object.
        * Collection - The "table" in the DB.
        * CollectionName - Collection name --> Collection.
        * QueryDocs - The query.
        * Sort - List of <paramsnames,true/false> to sort with, if true -> asc, if false -> desc.
        * Limit - The maximum number of items in results.
        * Skip - The number of items to skip after the sorting the result.
        * QueryResult<ResultsAsT> - The result of the query execute. <ResultsAsT> - the type of the results after deserialization.        
     */
    
    public class sqMongoQueryJob<ResultsAsT> : sqJob
    {
        public sqDB DB { get; set; }
        public string CollectionName { get; set; }
        public QueryDocument  QueryDocs { get; set; }
        public sqQueryTreeResult<ResultsAsT> QueryResult { get; set; }
        public MongoCollection<BsonDocument> Collection { get; set; }
        public int Limit { get; set; }
        public int Skip { get; set; }
        public List<Tuple<string,bool>> Sort { get; set; }
        
        /* Docs:
        * Summary: Initialize the job.
        */
        public sqMongoQueryJob(sqDB DB, string CollectionName = default(string), QueryDocument QueryDocs = default(QueryDocument), DateTime? QueryTime = null, int Limit = -1, int Skip = -1, List<Tuple<string, bool>> Sort = null)
            : base()
        {
            if (QueryTime == null)
                this.ExecuteTime = DateTime.Now;
            this.DB = DB;
            this.QueryDocs = QueryDocs;
            this.QueryResult = null;
            this.CollectionName = CollectionName;
            this.IsDone = false;
            MongoDatabase conn = this.DB.makeMongoConnection();
            Console.WriteLine(DB.ToJson());
            this.Collection = conn.GetCollection<BsonDocument>(this.CollectionName);
            this.Limit = Limit;
            this.Skip = Skip;
            this.Sort = Sort;
        }


        /* Docs:
        *Summary: Execute job and set results.
        */
        public sqMongoQueryJob(MongoCollection<BsonDocument> collection, QueryDocument QueryDocs = default(QueryDocument), DateTime? QueryTime = null, int Limit = -1, int Skip = -1, List<Tuple<string, bool>> Sort = null)
            : base()
        {
            if (QueryTime == null)
                this.ExecuteTime = DateTime.Now;
            this.QueryDocs = QueryDocs;
            this.QueryResult = null;
            this.CollectionName = CollectionName;
            this.IsDone = false;
            this.Collection = collection;
            this.Limit = Limit;
            this.Skip = Skip;
            this.Sort = Sort;
        }

        /* Docs:
        *Summary: Execute job and set results.
        * Variables:            
            * sortBy - List of fields nam, to sorting the results.
            * SortType - Ascending/Descending
            * limit - The max results num.
            * skip - Number for result to skip.
        */
        public void executeJob(int limit = default(int), int skip = default(int), string[] sortBy = default(string[]),sqHelpper.SortType SortType = sqHelpper.SortType.Descending)
        {
            List<ResultsAsT> results = new List<ResultsAsT>();
            MongoDatabase conn = this.DB.makeMongoConnection();
            MongoCollection<ResultsAsT> collection = conn.GetCollection<ResultsAsT>(this.CollectionName);
            MongoCursor<ResultsAsT> cur;
            if (this.QueryDocs != default(QueryDocument))
                cur = collection.FindAs<ResultsAsT>(QueryDocs);
            else
                cur = collection.FindAllAs<ResultsAsT>();
            if (sortBy != default(string[]))
                if (SortType == sqHelpper.SortType.Descending)
                    cur.SetSortOrder(SortBy.Descending(sortBy));
                else
                    cur.SetSortOrder(SortBy.Ascending(sortBy));
            if (limit != default(int))
                cur.SetLimit(limit);
            if (skip != default(int))
                cur.SetSkip(skip);
            foreach (ResultsAsT doc in cur)
            {
                results.Add(doc);
            }
            this.QueryResult = new sqQueryTreeResult<ResultsAsT>(results);
            this.ExecuteTime = DateTime.Now;
            
        }

        /* Docs:
        *Summary: Execute job and set results.
        * Variables:            
            * sortBy - List of fields nam, to sorting the results.
            * SortType - Ascending/Descending
            * limit - The max results num.
            * skip - Number for result to skip.
        */
        public override void executeJob()
        {
            List<ResultsAsT> results = new List<ResultsAsT>();
            MongoDatabase conn = this.DB.makeMongoConnection();
            MongoCollection<ResultsAsT> collection = conn.GetCollection<ResultsAsT>(this.CollectionName);
            MongoCursor<ResultsAsT> cur;
            if (this.QueryDocs != default(QueryDocument))
                cur = collection.FindAs<ResultsAsT>(QueryDocs);
            else
                cur = collection.FindAllAs<ResultsAsT>();
            if (this.Sort != null && this.Sort.GetType() == typeof(List<>) && this.Sort.Count() > 0)
                try
                {
                    foreach (Tuple<string, bool> t in this.Sort)
                    {
                        if (t.Item2 == false)
                            cur.SetSortOrder(SortBy.Ascending(t.Item1));
                        else
                            cur.SetSortOrder(SortBy.Descending(t.Item1));
                    }
                }
                catch { }
            if (this.Limit > 0)
                cur.SetLimit(this.Limit);
            if (Skip > 0)
                cur.SetSkip(this.Skip);
            foreach (ResultsAsT doc in cur)
            {
                results.Add(doc);
            }
            this.QueryResult = new sqQueryTreeResult<ResultsAsT>(results);
            this.ExecuteTime = DateTime.Now;
            this.IsDone = true;
        }


        /* Docs:
        *Summary: Rreturn query results.
        */
        public override object getResult()
        {
            return this.QueryResult;
        }

        /* Docs:
        *Summary: Return new instance that similar to this job befor execute.
        */
        public override sqJob renew()
        {
            return new sqMongoQueryJob<ResultsAsT>(this.DB, this.CollectionName, this.QueryDocs, Limit: this.Limit, Skip: this.Skip, Sort: this.Sort);
        }

        /* Docs:
        *Summary: Return new instance that equles to this job before/after execute.
        */
        public override sqJob copy()
        {
            sqMongoQueryJob<ResultsAsT> jobC = new sqMongoQueryJob<ResultsAsT>(this.DB,this.CollectionName, this.QueryDocs, this.ExecuteTime, Limit: this.Limit, Skip: this.Skip, Sort: this.Sort);
            jobC.IsDone = this.IsDone;
            jobC.QueryResult = this.QueryResult;
            return jobC;
        }
    }
}
